let someValue: any = 'this is a string';

// 强制转换
let strLength = (<string>someValue).length;
let strLength1 = (someValue as string).length;


console.log(strLength);
console.log(strLength1);

// 非空断言 : 参数 可以是字符串 undefined null
function myFunc(maybeString: string | undefined | null) {
  const onlyString: string = maybeString;
  const ignoreUndefinedAndNull: string = maybeString!;
  console.log(onlyString, ignoreUndefinedAndNull)
}

// tsconfig.json

myFunc(undefined);
myFunc('hello');

//in关键字

interface Admin {
  name: string;
  privileges: string[];
}

interface Employee {
  name: string;
  startDate: Date
}

// 联合类型
type UnknownEmployee = Employee | Admin;

function printEAngA(emp: UnknownEmployee) {
  console.log(emp.name);
  // in
  if ('privileges' in emp) {
    console.log('privileges', emp.privileges);
  }
  if ('startDate' in emp) {
    console.log('startDate', emp.startDate);
  }
}

printEAngA({name: '小三', startDate: new Date()});


// 联合类型
// 交叉类型

enum CarTransmission {
  Automatic = 200,
  Manual = 300
}

interface Motor {
  vType: 'motor';
  make: number;
}

interface Car {
  vType: 'car';
  transmission: CarTransmission;
}

interface Truck {
  vType: 'truck',
  capacity: number;
}

// 声明了一个联合类型
type Vehicle = Motor | Car | Truck;

const ENVAL = Math.PI;


function envalPrice(vehicle: Vehicle) {
  switch (vehicle.vType) {
    case 'motor':
      return vehicle.make * ENVAL;
    case 'car':
      return vehicle.transmission * ENVAL;
    case 'truck':
      return vehicle.capacity * ENVAL;
    default:
  }
}

let ve: Vehicle = {
  // vType:'truck',
  // capacity: 1000
  vType: 'car',
  transmission: CarTransmission.Manual
};

console.log(envalPrice(ve));


// 题 :

// 宠物 动物 共同的属性 :
// name age
// 猫 : 加菲猫 猪肉卷  无毛猫 : 线团 蓝猫 : 白兔
// 狗 : 柯基 : 香香的 金毛:臭臭的 斗牛 : 黄黄的 萨摩耶: 傻傻的
// 遛弯 : 函数  (animal:联合类型)
// 判断 带的是哪个动物  根据带的动物选择食物

enum CatType {
  GARFIELD = '猪肉卷',
  HAIRLESSCAT = '线团',
  BLUECAT = '白兔'
}

enum DogType {
  KIRKY = '香香的',
  GOLDEN = '臭臭的',
  Bulldog = '黄黄的',
  SAMOYE = '傻傻的'
}


interface Animal {
  name: string;
  age: number;
}

interface Dog extends Animal {
  typeDog: DogType;
  likeDogFood?: string;
}

interface Cat extends Animal {
  typeCat: CatType;
  likeCatFood: string;
}


type Pet = Dog | Cat;
type FOOD = CatType | DogType;

function takeWalk(pet: Pet): string {
  let myPet: string = '';
  let food: FOOD;

  if ('typeDog' in pet) {
    switch (pet.typeDog) {
      case  DogType.KIRKY :
        myPet = '柯基';
        food = DogType.KIRKY;
        break;
      case  DogType.GOLDEN :
        myPet = '金毛';
        food = DogType.GOLDEN;

        break;
      case  DogType.Bulldog :
        myPet = '斗牛';
        food = DogType.Bulldog;

        break;
      case  DogType.SAMOYE :
        myPet = '萨摩耶';
        food = DogType.SAMOYE;

        break;
    }
  }
  if ('typeCat' in pet) {
    switch (pet.typeCat) {
      case CatType.GARFIELD :
        myPet = '加菲猫';
        food = CatType.GARFIELD;
        break;
      case CatType.HAIRLESSCAT :
        myPet = '无毛猫';
        food = CatType.HAIRLESSCAT;
        break;
      case CatType.BLUECAT :
        myPet = '蓝猫';
        food = CatType.BLUECAT;
        break;
    }
  }
  return `今天要带${myPet}宠物带着${food}去遛弯`;

}

let pet: Pet = {
  name: '蓝猫',
  age: 3,
  typeCat: CatType.BLUECAT,
  likeCatFood: CatType.BLUECAT
};

console.log(takeWalk(pet));


// 设计一个函数 参数是回调 回调的参数必须是string 回调的返回值是string
// 该函数返回值是字符串数组

// 声明函数类型

// 泛型  规范
// type FN_TYPE = <T>(str:T)=>T
//
//
// let call = (callback: FN_TYPE): string[] => {
//   return ['1']
// };
//
// call(<T>(str: T): T=> {
//   return ;
// });

// 泛型 : 不是只定义变量 得到一个规范类型
function identity<T, U>(value: T, message: U): T {
  console.log(message);
  return value;
}

interface Person {
  name: string;
  age: number;
}

let code = identity<Person, String>({name: '小李', age: 20}, '上山打老鼠');


// 泛型接口  T U Y

interface Generator<T> {
  arg: T
}

let a: Generator<String> = {
  arg: '123'
};


// 泛型类

class Gen<T, U> {
  zeroValue: T;
  add: (x: T, y: T) => U
}

let gen = new Gen<number, boolean>();
gen.zeroValue = 123;
gen.add = function (x, y) {
  return x + y > 3
};


// typeof


interface Person {
  name: string;
  age: number;
}

const sem: Person = {name: 'sm', age: 13};

console.log(typeof sem);

type Sem = typeof sem; // Person

// console.log()
// let sem1 : Sem = 'object'

//keyof  typescript 2.1 (4) 之后引入的 该操作符 可以获取某种类型的所有键  Object.keys 返回的类型就是联合类型
type K1 = keyof Person;  // name|age
type K2 = keyof Person[]; // length | toString | pop | push
type K3 = keyof { [x: string]: Person; }; // string | number

let k1: K2 = 'toString';
let k3: K3 = 123;


interface AA {
  [x: string]: Person;
}

let aa: AA = {a: {name: '123', age: 12}};





